﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Interface;
using PServiceBus.Core.Runtime.Configuration;
using System.Collections;
using System.Collections.Concurrent;
using PServiceBus.Core.Runtime;
using System.Reflection;
using Phoenix.ReflectionExtensions;
using PServiceBus.Core.Runtime.Extensions;

namespace PServiceBus.Core.Configuration {
    public class XmlFileConfiguration : IConfiguration {

        private readonly List<IDictionary<string, object>> _configuration;

        private const BindingFlags PROPERTY_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;

        public XmlFileConfiguration() {

        }

        public XmlFileConfiguration(string filename) {
            _configuration = ConfigurationParser.Process(filename).ToList();
        }

        private TReturn GetConfig<TParam, TReturn>(string sectionName) where TReturn : class where TParam : class {
            var returnType = typeof(TReturn);
            var isCollection = typeof(IEnumerable).IsAssignableFrom(returnType);
            var dict = _configuration.FirstOrDefault(x => x.ContainsKey(sectionName));
            var section = dict != null ? dict[sectionName] : null;
            if (section == null) {
                if (isCollection)
                    return new List<TParam>() as TReturn;
                return default(TReturn);
            }
            
            if (isCollection) {
                var listResult = new List<TParam>();

                if (typeof(IList).IsAssignableFrom(section.GetType())) {
                    var list = (section as IList).Cast<IDictionary<string, object>>();
                    foreach (var item in list)
                        listResult.Add(SectionTo<TParam>(item));
                } else 
                    listResult.Add(SectionTo<TParam>(section as IDictionary<string, object>));
                
                return listResult as TReturn;
            }
            return SectionTo<TReturn>(section as IDictionary<string, object>);
        }

        private TReturn GetConfig<TReturn>(string sectionName) where TReturn : class {
            return GetConfig<TReturn, TReturn>(sectionName);
        }

        private TReturn SectionTo<TReturn>(IDictionary<string, object> section) where TReturn : class {
            var dict = section.ToDictionary(kv => kv.Key, kv => kv.Value.ToString());

            return ReflectionHelper.New<TReturn>(o => {
                var type = o.GetType();
                foreach (var kv in dict) {
                    var prop = type.GetProperty(kv.Key, PROPERTY_FLAGS);
                    if (prop == null) continue;
                    prop.SetValueEx(o, kv.Value.ChangeType(prop.PropertyType));
                }
            });
        }

        #region IConfiguration Members

        public IServiceBusConfig ServiceBusConfig {
            get { return GetConfig<IServiceBusConfig>("serviceBusConfig"); }
        }

        public ILoggerConfig LoggerConfig {
            get { return GetConfig<ILoggerConfig>("loggerConfig"); }
        }

        public IComponentContainerConfig ComponentContainerConfig {
            get { throw new NotImplementedException(); }
        }

        public IComponentConfig ComponentConfig {
            get { throw new NotImplementedException(); }
        }

        public IDistributorConfig DistributorConfig {
            get { return GetConfig<IDistributorConfig>("distributorConfig"); }
        }

        public IList<IMessageStoreConfig> MessageStoreConfigs {
            get { return GetConfig<IMessageStoreConfig, IList<IMessageStoreConfig>>("store"); }
        }

        public IList<ISubscriptionManagerConfig> SubscriptionConfigs {
            get { return GetConfig<ISubscriptionManagerConfig, IList<ISubscriptionManagerConfig>>("manager"); }
        }

        public ISecurityConfig SecurityConfig {
            get { return GetConfig<ISecurityConfig>("securityConfig"); }
        }

        public IList<IObserverConfig> ObserverConfigs {
            get { return GetConfig<IObserverConfig, IList<IObserverConfig>>("observerConfig"); }
        }

        public IList<ITopicMessageEnricherConfig> TopicEnricherConfigs {
            get { return GetConfig<ITopicMessageEnricherConfig, IList<ITopicMessageEnricherConfig>>("enricher"); }
        }

        public IList<ITopicMessageInspectorConfig> TopicMessageInspectorConfigs {
            get { return GetConfig<ITopicMessageInspectorConfig, IList<ITopicMessageInspectorConfig>>("inspector"); }
        }

        public IList<IWebStreamManagementConfig> WebStreamManagementConfigs {
            get { return GetConfig<IWebStreamManagementConfig, IList<IWebStreamManagementConfig>>("stream"); }
        }

        #endregion
    }
}
